﻿using NLog;
using SnmpSharpNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace ServerMonitor
{
    public class SnmpService
    {
        private static ILogger logger = LogManager.GetCurrentClassLogger();
        private static string incomingBytesOid = "1.3.6.1.2.1.31.1.1.1.6";
        private static string outgoingBytesOid = "1.3.6.1.2.1.31.1.1.1.10";
        private static string portStatusOid = "1.3.6.1.2.1.2.2.1.8";

        public static void getSwitchStatus(SnmpBean snmpBean)
        {
            snmpBean.UpdateTime = DateTime.Now.ToString();
            //snmpBean.PortStatus = new int[snmpBean.PortCount]; //初始化snmpbean中的端口状态数组
            snmpBean.IsConnected = PingService.TestNetConnectity(snmpBean.IpAddress);
            try
            {
                Dictionary<string, string> resultMap = getOIDValue(snmpBean.IpAddress, snmpBean.Oids);
                Dictionary<string, string> portStatusMap = getWalkValue(snmpBean.IpAddress, portStatusOid, snmpBean.PortCount);
                if (resultMap.Count < 1 )
                {
                    snmpBean.IsConnected = false;
                }
                else
                {
                    int usedMemory = int.Parse(resultMap[snmpBean.UsedMemoryCommand]);
                    int freeMemory = int.Parse(resultMap[snmpBean.FreeMemoryCommand]);
                    int cpuLoad = int.Parse(resultMap[snmpBean.CpuLoadCommand]);
                    int temperature = int.Parse(resultMap[snmpBean.TemperatureCommand]);
                    int memoryUsage = (usedMemory * 100) / (usedMemory + freeMemory);
                    snmpBean.ReslutTotalMemory = usedMemory + freeMemory;
                    snmpBean.ResultAvailableMemory = freeMemory;
                    snmpBean.ResultMemoryUsage = memoryUsage;
                    snmpBean.ResultCpuLoad = cpuLoad;
                    snmpBean.ResultTemperature = temperature;
                    processPortStatus(snmpBean,portStatusMap);
                    //snmpBean.IsConnected = true;
                }
            }
            catch (Exception e)
            {
                //snmpBean.IsConnected = false;
                logger.Error("snmp service error:switch{0},{1},{2}",snmpBean.IpAddress,e.Message,e.StackTrace.ToString());
            }
        }

        public static void processPortStatus(SnmpBean snmpBean , Dictionary<string, string> portStatusMap)
        {
            foreach (KeyValuePair<string,string> entry in portStatusMap)
            {
                string portNum = entry.Key.Substring(entry.Key.LastIndexOf(".") + 1); //获取端口号
                snmpBean.PortStatus[int.Parse(portNum) - 1] = int.Parse(entry.Value);
            }
        }

        public static void getSwitchFlow(SnmpBean snmpBean)
        {
            string key = getKeyOfTimeStamp();
        }

        private static string getKeyOfTimeStamp()
        {
            string key = "";

            return key;
        }

        #region 通过oid字符数组获得相应的值   
        public static Dictionary<string, string> getOIDValue(string host, string[] oid)
        {
            //返回变量   
            Dictionary<string, string> dic = new Dictionary<string, string>();

            // SNMP community name   
            OctetString community = new OctetString("public");

            // Define agent parameters class   
            AgentParameters param = new AgentParameters(community);
            // Set SNMP version to 1 (or 2)   
            param.Version = SnmpVersion.Ver1;
            // Construct the agent address object   
            // IpAddress class is easy to use here because   
            //  it will try to resolve constructor parameter if it doesn't   
            //  parse to an IP address   
            IpAddress agent = new IpAddress(host);

            // Construct target   
            UdpTarget target = new UdpTarget((IPAddress)agent, 161, 2000, 1);

            // Pdu class used for all requests   
            Pdu pdu = new Pdu(PduType.Get);

            foreach (string singleoid in oid)
            {
                pdu.VbList.Add(singleoid);
            }

            // Make SNMP request   
            SnmpV1Packet result = (SnmpV1Packet)target.Request(pdu, param);

            // If result is null then agent didn't reply or we couldn't parse the reply.   
            if (result != null)
            {
                // ErrorStatus other then 0 is an error returned by    
                // the Agent - see SnmpConstants for error definitions   
                if (result.Pdu.ErrorStatus == 0)
                {
                    for (int i = 0; i < result.Pdu.VbList.Count; i++)
                    {
                        dic.Add(result.Pdu.VbList[i].Oid.ToString(), result.Pdu.VbList[i].Value.ToString());
                    }
                    // Reply variables are returned in the same order as they were added   
                    //  to the VbList   
                }
            }
            target.Close();
            return dic;
        }
        #endregion

        #region 通过snmpwalk返回oid根下面的所有值   
        public static Dictionary<string, string> getWalkValue(string host, string irootOid,int count)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            // SNMP community name   
            OctetString community = new OctetString("public");

            // Define agent parameters class   
            AgentParameters param = new AgentParameters(community);
            // Set SNMP version to 2 (GET-BULK only works with SNMP ver 2 and 3)   
            param.Version = SnmpVersion.Ver2;
            // Construct the agent address object   
            // IpAddress class is easy to use here because   
            //  it will try to resolve constructor parameter if it doesn't   
            //  parse to an IP address   
            IpAddress agent = new IpAddress(host);

            // Construct target   
            UdpTarget target = new UdpTarget((IPAddress)agent, 161, 2000, 1);

            // Define Oid that is the root of the MIB   
            //  tree you wish to retrieve   
            Oid rootOid = new Oid(irootOid); // ifDescr   

            // This Oid represents last Oid returned by   
            //  the SNMP agent   
            Oid lastOid = (Oid)rootOid.Clone();

            // Pdu class used for all requests   
            Pdu pdu = new Pdu(PduType.GetBulk);

            // In this example, set NonRepeaters value to 0   
            pdu.NonRepeaters = 0;
            // MaxRepetitions tells the agent how many Oid/Value pairs to return   
            // in the response.   
            pdu.MaxRepetitions = count;

            // Loop through results   
            while (lastOid != null)
            {
                // When Pdu class is first constructed, RequestId is set to 0   
                // and during encoding id will be set to the random value   
                // for subsequent requests, id will be set to a value that   
                // needs to be incremented to have unique request ids for each   
                // packet   
                if (pdu.RequestId != 0)
                {
                    pdu.RequestId += 1;
                }
                // Clear Oids from the Pdu class.   
                pdu.VbList.Clear();
                // Initialize request PDU with the last retrieved Oid   
                pdu.VbList.Add(lastOid);
                // Make SNMP request   
                SnmpV2Packet result = (SnmpV2Packet)target.Request(pdu, param);
                // You should catch exceptions in the Request if using in real application.   

                // If result is null then agent didn't reply or we couldn't parse the reply.   
                if (result != null)
                {
                    // ErrorStatus other then 0 is an error returned by    
                    // the Agent - see SnmpConstants for error definitions   
                    if (result.Pdu.ErrorStatus == 0)
                    {
                        // Walk through returned variable bindings   
                        foreach (Vb v in result.Pdu.VbList)
                        {
                            // Check that retrieved Oid is "child" of the root OID   
                            if (rootOid.IsRootOf(v.Oid))
                            {
                                //dic.Add(v.Oid.ToString(), v.Value.ToString());
                                dic[v.Oid.ToString()] = v.Value.ToString();
                            }
                            //else
                            //{
                            //    // we have reached the end of the requested   
                            //    // MIB tree. Set lastOid to null and exit loop   
                            //    lastOid = null;
                            //}
                        }
                        lastOid = null;
                    }
                }
            }
            target.Close();
            return dic;
        }
        #endregion
    }

}
